package com.jt.service.impl;

import com.jt.service.FileService;
import com.jt.vo.ImageVO;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;

/**
 * @author 张琪
 * @date 2020/12/1
 * @describe
 */
@Service
//@PropertySource(value = "classpath://properties/image.properties", encoding = "utf-8")
@PropertySource(value = "properties/image", encoding = "utf-8")
public class FileServiceImpl implements FileService {

    private static Set<String> typeSet = new HashSet<>();

    static {
        typeSet.add(".jpg");
        typeSet.add(".png");
        typeSet.add(".gif");
    }

    @Value("${image.fileDir}")
    String fileDir;

    @Value("${image.urlPath}")
    String urlPath;

    /**
     * 业务逻辑: 实现文件上传
     * 步骤:
     * 1. 校验图片类型 jpg/png/gif...
     * 2. 校验文件是否为恶意程序
     * 3. 采用分目录的结构进行存储
     * 4. 避免文件重名 UUID
     *
     * @param multipartFile
     * @return
     */
    @Override
    public ImageVO upload(MultipartFile multipartFile, String dir) {
        /* 可能存在的bug: 因为系统的不同, 导致文件的后缀可能为大写, 从而导致结果的不匹配*/
//        1. 校验图片类型  1.获取文件后缀,  进行比较     2. 正则表达式
//        1.1 获取文件名称        .jpg  .JPG
        String filename = multipartFile.getOriginalFilename();
        filename.toLowerCase();
//        1.2 获取文件后缀        获取最后的 '.'
        int index = filename.lastIndexOf(".");
//        1.3 获取文件后缀类型        通过 '.' 来分隔
        String fileType = filename.substring(index);
//        1.4 判断后缀是否匹配
        if (!typeSet.contains(fileType)) {
            return ImageVO.fault();
        }

//        2. 如果是图片,   需要获取图片的高度和宽度
        int width;
        int height;

        try {
            BufferedImage bufferedImage = ImageIO.read(multipartFile.getInputStream());
            width = bufferedImage.getWidth();
            height = bufferedImage.getHeight();
//            图片尺寸不匹配时, 弹出错误
            if (width == 0 || height == 0) {
                return ImageVO.fault();
            }
        } catch (IOException e) {
//            出现异常时 弹出错误
            e.printStackTrace();
            return ImageVO.fault();
        }


//        3. 实现分目录的存储
//        String fileDir = "F:/image";

//        3.1 使用hash算法 来生成分目录    8位16进制数   每两位进行划分
//        3.2 使用日期方式进行目录划分
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("/yyyy/MM/dd/");/*使用/来拼接, 方便之后拼接更加方便*/
        String dateDir = simpleDateFormat.format(new Date());
//        3.3 生成文件路径
        /*读取配置文件来获取fileDir*/
        String fileDirPath = fileDir + dateDir;
//        3.4 创建文件目录
        File dirFile = new File(fileDirPath);
        if (!dirFile.exists()) {
            dirFile.mkdirs();
        }


//        4. 实现文件上传
//        4.1 准备文件名称  使用UUID动态生成
        String uuid = UUID.randomUUID().toString().replace("-", "");
        String uuidName = uuid + fileType;
        File file = new File(fileDirPath + uuidName);
        try {
            multipartFile.transferTo(file);
        } catch (IOException e) {
            e.printStackTrace();
        }

//        String url = "http://renote.jp/uploads/image/file/70918/8UyvUCf.jpg";
        String url = urlPath + dir + dateDir + uuidName;
        return ImageVO.success(url, width, height);
    }

    @Override
    public ImageVO upload1(String dir, MultipartFile multipartFile) {
        /*1. 参数校验   传入的是图片格式, 校验后缀*/
        String filename = multipartFile.getOriginalFilename();
        // lastIndexOf(), 获取最后一个出现响应字符的下标, 获取最后一个 .
        int index = filename.lastIndexOf(".");
        // subString() 左包含,右不包含,  获取到.jpg 等类似的后缀
        String fileType = filename.substring(index);

//        与预设的后缀名进行判断, 不匹配则返回异常
        if (!typeSet.contains(fileType)) {
            return ImageVO.fault();
        }

        /*2. 获取文件参数*/
//        2.1 获取图片流
        BufferedImage bufferedImage = null;
        try {
            bufferedImage = ImageIO.read(multipartFile.getInputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
//        2.2 根据图片流获取文件参数(宽/高)
        int width = bufferedImage.getWidth();
        int height = bufferedImage.getHeight();

        /*3. 创建存储路径*/
//        3.1 获得根路径, 这里的根路径即为传入的参数, 所以下句省略不写
//        String fileDir = dir;
//        3.2 根据日期格式来创建新的目录, 保证每个文件中的文件数量
        String dateDir = new SimpleDateFormat("/yyyy/MM/dd/").format(new Date());
//        3.3 拼接为相对路径
        String fileDirPath = "./src/main/webapp/" + dir + dateDir;
        File dirFile = new File(fileDirPath);
        if (!dirFile.exists()) {
            dirFile.mkdirs();
        }

        /*4. 生成随机文件名*/
        String uuid = UUID.randomUUID().toString().replace("-", "");
        String filePath = dirFile.getAbsolutePath() + "/" + uuid + fileType;
        File file = new File(filePath);
        try {
            multipartFile.transferTo(file);
        } catch (IOException e) {
            e.printStackTrace();
        }

        String url = "/" + dir + dateDir + uuid + fileType;
        return ImageVO.success(url, width, height);
    }
}
